/*
TODO
groups d'objects avec attribut noms
zone rectangulaire de limite de mouvement d'objets (pour d�charger le module Scene)
positionnement d'objets relativement au pere (=nouvelle fonction)
chargement du monde par xml => lib xml (moteur de parsing a faire/trouver)
ajouter partout les controles d'erreurs (==null et autres)
ajouter commentaires javadoc
supprimer tous les acces directs aux attributs intermodules (passer par des m�thodes)
*/


package com.brainydroid.framework;

import java.io.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collections;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GLCommon;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.*;


/**
 * Main Class of the experiment
 * Manage object display, i/o, sounds etc
 */
public abstract class Scene implements ApplicationListener {

	private SpriteBatch batcher_;

	int H_SCREEN = 480;
	int W_SCREEN = 800;		
	
    public static float scalex_;
    public static float scaley_;
	
	public Create create_;

	// User inputs
	public EventManager events_;
	// Rendering engine
	public GraphicManager graphics_;
	// Audio
	 AudioManager audio_;
	// World data
	protected ArrayList<Object> objects_;
	
	// Other attributes
	private float time_;  // global time
	
    public int N_trials_; // number of trials
    public int N_screens_; // number of screens per trial
    public int i_trial_; // index of ongoing trial
    public int i_screen_; // index of ongoing screen
    
   

	/**
	 * Constructor (empty)
	 */
	public Scene() {	
	}

	
	/**
	 * Initialize all the elements of the class scene
	 */
	public void create() {
		
		scalex_ = (float)Gdx.graphics.getWidth() / 800f;
        scaley_ = (float)Gdx.graphics.getHeight() / 480f;

		
		batcher_ = new SpriteBatch(); // init display
		create_ = new Create(this);
		// Init variables
		time_ = 0.0f;
		// Init modules
		events_ = new EventManager(this);
//		audio_ = new AudioManager(this, game.getAudio());
		graphics_ = new GraphicManager(this);
		// Objects
		objects_ = new ArrayList<Object>();
		
		init_experiments();
		
		graphics_.init();
		events_.init();
	}
	
	
	/**
	 * Called after experiment_loop, this function manages io and display
	 */
	 @Override
		public void render() {
		// Manage touchevent
		events_.processEvents(Gdx.graphics.getDeltaTime()); // this process touch events
		// Experiment check
		experiment_loop();
		// display
		update(Gdx.graphics.getDeltaTime());  // this updates graphic display
		batcher_.begin();
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		present(0f,batcher_);
		batcher_.end();	
		}
	
	/**
	 * This is where the script of the experiment has to be written
	 */
	 public abstract void experiment_loop();
	 
	 /**
	  * This is where the script of the initialization of objects has to be written
	  */
	 public abstract void init_experiments();		
	
	 
	
	/**
	 Adds an object to the vector of objects
	 @param o
	*/
	public Object addObject(Object o) {
		objects_.add(o);
		return objects_.get(objects_.size()-1);
	}
	
	
	/**
	 Returns the touchable object at the given position on scene
	 Returns null if no touchable objects in range
	 @param x
	 @param y
	*/
	 Object getObjectAtPositionForSelection(int x, int y) {
         for (Object o : events_.objects_) {
                 if (o.touchable_) {
                	 if (o.istouch((float)x,(float)y ,scalex_,scaley_)) {
                		 return o;
                	 }
                 }
         }
         return null;
	 }

	/**
	 Returns the the ROOT object (oldest family relative) touchable object at the given position on scene
	 Returns null if no touchable objects in range
	 @param x
	 @param y
	*/	
	Object getObjectAtPositionForMove(int x, int y) {
			return getObjectAtPositionForSelection(x, y).getMoveRoot(); 
	}
	
		
	/**
	 * Performs updates of all objects in the task
	 */
	public void update(float deltatime) {						
		// Physics
		for (Object o : objects_) {
			o.update(deltatime);
		}			
		time_ += deltatime;
		
	}

	/**
	 * Display
	 */
	public void present(float deltatime, SpriteBatch batch) { 
		graphics_.drawObjects(time_, batch);
	}
	
	/**
	 * What happens when experiment is paused
	 */
	@Override
	public void pause() {
		// TODO Lib�rer les pixmaps et sons
	}

	/**
	 * What happens when experiment is resumed
	 */
	@Override
	public void resume() {
		// TODO recharger les pixmaps
	}
	

	/**
	 * Sets time of the experiment
	 * @param t
	 */
	public void setTime(float t) {
		time_ = t;
	}
	
	/**
	 * Returns ongoing time
	 * @return
	 */
	public float getTime() {
		return time_;
	}
	
	
	/** 
	 * Terminates the AndroidApplication
	 * @see AndroidApplication
	 */
	@Override
	public void dispose() {
		Gdx.app.exit();		
	}
	
	/**
	 * Returns x coordinate of virtual screen center
	 * @return
	 */
	public int getScreenCenter_x(){
		return Gdx.graphics.getWidth()/2;
	}
	
	/**
	 * Returns y coordinate of virtual screen center
	 * @return
	 */
	public int getScreenCenter_y(){
		return Gdx.graphics.getHeight()/2;
	}
	
	@Override
	public void resize(int arg0, int arg1) {
		// TODO Auto-generated method stub
		
	}
}
